package com.apes.fn.scm.merchant.settlement.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.business.insurance.modle.InsuranceOrder;
import com.apes.fn.business.insurance.repository.InsuranceOrderRepository;
import com.apes.fn.fico.debitnote.model.BusinessDebitNote;
import com.apes.fn.fico.debitnote.model.DeductionDetail;
import com.apes.fn.fico.debitnote.repository.BusinessDebitNoteRepository;
import com.apes.fn.fico.expense.*;
import com.apes.fn.fico.settleExpense.SettleExpenseRepository;
import com.apes.fn.scm.contract.FnContract;
import com.apes.fn.scm.contract.FnContractRepository;
import com.apes.fn.scm.merchant.account.service.AccountSettlementService;
import com.apes.fn.scm.merchant.settlement.model.CostSummary;
import com.apes.fn.scm.merchant.settlement.model.MerchantBusinessDebitItem;
import com.apes.fn.scm.merchant.settlement.model.MerchantExpenseItem;
import com.apes.fn.scm.merchant.settlement.model.MerchantSettlement;
import com.apes.fn.scm.merchant.settlement.repository.MerchantExpenseItemRepository;
import com.apes.fn.scm.merchant.settlement.repository.MerchantSettlementDao;
import com.apes.fn.scm.merchant.settlement.repository.MerchantSettlementRepository;
import com.apes.fn.scm.retailOrder.repository.ReportDaliyDao;
import com.apes.fn.scm.settleCheck.model.PartnerCheck;
import com.apes.fn.scm.settleCheck.reponsitory.PartnerCheckRepository;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.generator.service.SequenceService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.OutboxSubscriberService;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.Arith;
import com.apes.framework.util.DateUtil;
import com.apes.framework.util.MapUtil;
import com.apes.scm.account.account.model.InventoryMode;
import com.apes.scm.account.account.repository.InventoryBatchRepository;
import com.apes.scm.invoice.model.Invoice;
import com.apes.scm.invoice.repository.InvoiceRepository;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.EnumerationRepository;
import com.apes.scm.masterdata.party.model.AccessProvider;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.AccessProviderRepository;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.rbac.model.Post;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.PostRepository;
import com.apes.scm.rbac.repository.UserRepository;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.repository.VoucherRepository;
import com.apes.scm.voucher.service.VoucherType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.ObjectUtils;

import javax.persistence.EntityManager;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @BelongsProject: apes-server
 * @BelongsPackage: com.apes.fn.scm.merchant.settlement.service
 * @ClassName: MerchantSettlementService
 * @Author: pyb
 * @Description: 赋能商户结算对账业务层
 * @CreateTime: 2020-10-29 15:11
 * @Version: 1.0
 */
@Service("merchantSettlementService")
public class MerchantSettlementService extends DomainService {
    private MerchantSettlementRepository merchantSettlementRepository;

    @Autowired
    private void setMerchantSettlementRepository(MerchantSettlementRepository merchantSettlementRepository) {
        this.merchantSettlementRepository = merchantSettlementRepository;
    }


    EntityManager entityManager;

    @Autowired
    private void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }


    VoucherRepository voucherRepository;

    @Autowired
    private void setVoucherRepository(VoucherRepository voucherRepository) {
        this.voucherRepository = voucherRepository;
    }

    PartnerCheckRepository partnerCheckRepository;

    @Autowired
    private void setPartnerCheckRepository(PartnerCheckRepository partnerCheckRepository) {
        this.partnerCheckRepository = partnerCheckRepository;
    }

    ExpenseItemRepository expenseItemRepository;

    @Autowired
    private void setExpenseItemRepository(ExpenseItemRepository expenseItemRepository) {
        this.expenseItemRepository = expenseItemRepository;
    }

    BusinessDebitNoteRepository businessDebitNoteRepository;

    @Autowired
    private void setBusinessDebitNoteRepository(BusinessDebitNoteRepository businessDebitNoteRepository) {
        this.businessDebitNoteRepository = businessDebitNoteRepository;
    }

    @Autowired
    MerchantSettlementDao merchantSettlementDao;

    @Autowired
    ExpenseRepository expenseRepository;

    @Autowired
    InvoiceRepository invoiceRepository;
    @Autowired
    InsuranceOrderRepository insuranceOrderRepository;
    @Autowired
    SettleExpenseRepository settleExpenseRepository;

    @Autowired
    ExpenseService expenseService;

    @Autowired
    private PartyRoleRepository partyRoleRepository;
    @Autowired
    private FnContractRepository fnContractRepository;


    /**
     * 保存方法
     *
     * @param request
     * @return
     */
    public MerchantSettlement save(SimpleRequest request) {
        MerchantSettlement merchantSettlement = request.getO(MerchantSettlement.class);
        merchantSettlement.setState("sent");
        merchantSettlement.setReconcileUid(request.getPerson());
        merchantSettlement.setReconcileDate(new Date());
        processingExpenseBill(merchantSettlement, 1);
        merchantSettlement.computeAmt();
        return merchantSettlementRepository.saveAndFlush(merchantSettlement);
    }

    /**
     * 修改方法
     *
     * @param request
     * @return
     */
    public MerchantSettlement update(SimpleRequest request) {
        MerchantSettlement merchantSettlement = request.getO(MerchantSettlement.class);
        if (!merchantSettlementRepository.findByMerchantAndReconcileDate(merchantSettlement.getMerchant().getId(), merchantSettlement.getReconcileBeginDate()).isEmpty()){
            throw new RuntimeException("后续账期已对账,此账期不允许更改操作!");
        }
        processingExpenseBill(merchantSettlementRepository.findOne(merchantSettlement.getId()), -1);
        merchantSettlement.setReconcileUid(request.getPerson());
        merchantSettlement.setReconcileDate(new Date());
        processingExpenseBill(merchantSettlement, 1);
        merchantSettlement.computeAmt();
        return merchantSettlementRepository.saveAndFlush(merchantSettlement);
    }

    /**
     * 财务审核方法
     *
     * @param request
     * @return
     */
    public MerchantSettlement approval(SimpleRequest request) {
        MerchantSettlement merchantSettlement = request.getO(MerchantSettlement.class);
        merchantSettlement.setState("financialAudit");
        merchantSettlement.setFinancialAuditUid(request.getPerson());
        if (merchantSettlement.getFinancialAuditDate() == null) {
            merchantSettlement.setFirstFinancialAuditDate(new Date());
        }
        merchantSettlement.setFinancialAuditDate(new Date());

        //获取该商户下赋能店对账岗位
        List<Post> postList = SpringManager.getBean(PostRepository.class).findAll(JpaDsl.toCriteriaByEq("company.id", merchantSettlement.getMerchant().getId())).stream().filter(post -> "0000792".equals(post.getWorkPost().getId())).collect(Collectors.toList());
        List<User> userList = new ArrayList<>();
        for (Post post : postList) {
            List<User> users = SpringManager.getBean(UserRepository.class).findByPost(post.getId());
            userList.addAll(users);
        }
        JSONArray array = userList.stream().distinct().map(User::getId).collect(Collectors.toCollection(JSONArray::new));
        merchantSettlement = merchantSettlementRepository.saveAndFlush(merchantSettlement);
        merchantSettlement.setCandidates(JSON.toJSONString(array));
        return merchantSettlement;
    }

    /**
     * 商户确认方法
     *
     * @param request
     * @return
     */
    public MerchantSettlement merchantConfirmation(SimpleRequest request) {
        checkData(request);
        MerchantSettlement merchantSettlement = request.getO(MerchantSettlement.class);
        //检查上期单据是否已确认
        merchantSettlementRepository.findOne(JpaDsl.toCriteriaByEq("merchant.id",merchantSettlement.getMerchant().getId(),"reconcileEndDate",DateUtil.add(merchantSettlement.getReconcileBeginDate(), Calendar.DAY_OF_MONTH, -1))).ifPresent(m->{
            if ("sent".equals(m.getState()) || "financialAudit".equals(m.getState())) {
                throw new RuntimeException(String.format("上期对账单[%s]未确认，请先确认上期对账单！",m.getId()));
            }
        });
        merchantSettlement.setState("confirmation");
        merchantSettlement.setMerchantConfirmationUid(request.getPerson());
        merchantSettlement.setMerchantConfirmationDate(new Date());
        return merchantSettlementRepository.saveAndFlush(merchantSettlement);
    }

    /**
     * 商户驳回方法
     *
     * @param request
     * @return
     */
    public MerchantSettlement merchantReject(SimpleRequest request) {
        checkData(request);
        MerchantSettlement merchantSettlement = request.getO(MerchantSettlement.class);
        merchantSettlement.setState("sent");
        merchantSettlement.setMerchantConfirmationUid(request.getPerson());
        merchantSettlement.setMerchantConfirmationDate(new Date());
        return merchantSettlementRepository.saveAndFlush(merchantSettlement);
    }

    /**
     * 客服审核方法
     * 已弃用
     *
     * @param request
     * @return
     */
    public MerchantSettlement serviceApprove(SimpleRequest request) {
//        checkData(request);
        MerchantSettlement merchantSettlement = request.getO(MerchantSettlement.class);
//        merchantSettlement.setState("serviceApprove");
//        settlement.setServiceApproveUid(request.getPerson());
//        settlement.setServiceApproveDate(new Date());
        return merchantSettlementRepository.findOne(merchantSettlement.getId());
    }

    /**
     * 删除方法
     *
     * @param request
     * @return
     */
    public String delete(SimpleRequest request) {
        checkData(request);
        MerchantSettlement merchantSettlement = request.getO(MerchantSettlement.class);
        if (!merchantSettlementRepository.findByMerchantAndReconcileDate(merchantSettlement.getMerchant().getId(), merchantSettlement.getReconcileBeginDate()).isEmpty()){
            throw new RuntimeException("后续账期已对账,此账期不允许更改操作!");
        }
        processingExpenseBill(merchantSettlement, -1);
        merchantSettlementRepository.delete(merchantSettlement);
        return "删除成功";
    }

    /**
     * 数据检查
     *
     * @param request
     */
    public void checkData(SimpleRequest request) {
        String id = request.get("id");
        MerchantSettlement merchantSettlement = merchantSettlementRepository.findOne(id);
        long version = (int) request.get("version");
        Optional.ofNullable(merchantSettlement).orElseThrow(() -> new RuntimeException(String.format("赋能商户结算对账单[%s]在系统中不存在,请检查数据", id)));
        if (merchantSettlement.getVersion() != version) {
            throw new RuntimeException("记录已更新或已删除，请重新提交！");
        }

    }

    /**
     * 清账
     *
     * @param request
     */
    public MerchantSettlement squareAccounts(SimpleRequest request) {
        checkData(request);
        MerchantSettlement merchantSettlement = request.getO(MerchantSettlement.class);
        merchantSettlement.getMerchantExpenseItems().forEach(merchantExpenseItem -> {
            ExpenseItem expenseItem = merchantExpenseItem.getExpenseItem();
            expenseItem.setWithholdingAmount(expenseItem.getWithholdingAmount() - merchantExpenseItem.getCurrentAmount());
            expenseItem.setAmountDeducted(expenseItem.getAmountDeducted() + merchantExpenseItem.getCurrentAmount());
            expenseItem.setArrivalDate(new Date());
            expenseItemRepository.saveAndFlush(expenseItem);
            Expense expense = expenseItem.getExpense();
            expense.checkDeduct();
            expenseRepository.saveAndFlush(expense);
        });
        /*processingDeductionDetail(merchantSettlement);*/
        merchantSettlement.setState("squareAccounts");
        merchantSettlement.setSquareAccountsDate(new Date());
        merchantSettlement.setSquareAccountsUid(request.getPerson());
        return merchantSettlementRepository.saveAndFlush(merchantSettlement);
    }

    /**
     * 处理费用单与借支单
     *
     * @param merchantSettlement
     */
    public void processingExpenseBill(MerchantSettlement merchantSettlement, double changeQty) {
        merchantSettlement.getMerchantExpenseItems().forEach(merchantExpenseItem -> {
            ExpenseItem expenseItem = merchantExpenseItem.getExpenseItem();
            expenseItem.setWithholdingAmount(expenseItem.getWithholdingAmount() + (merchantExpenseItem.getCurrentAmount() * changeQty));
            expenseItemRepository.saveAndFlush(expenseItem);
        });

        merchantSettlement.getMerchantBusinessDebitItems().forEach(merchantBusinessDebitItem -> {
            BusinessDebitNote businessDebitNote = merchantBusinessDebitItem.getBusinessDebitNote();
            businessDebitNote.setPrepaidPrincipal(businessDebitNote.getPrepaidPrincipal()+(merchantBusinessDebitItem.getCurrentAmount() * changeQty));
            businessDebitNoteRepository.saveAndFlush(businessDebitNote);
        });
    }


    /**
     * 处理扣收明细
     *
     * @param merchantSettlement
     */
    public void processingDeductionDetail(MerchantSettlement merchantSettlement) {
        merchantSettlement.getMerchantBusinessDebitItems().forEach(merchantBusinessDebitItem -> {
            BusinessDebitNote businessDebitNote = merchantBusinessDebitItem.getBusinessDebitNote();
            DeductionDetail deductionDetail = new DeductionDetail();
            deductionDetail.setId(SpringManager.getBean(SequenceService.class).getId(BusinessDebitNote.CONST_TABLE_NAME));
            deductionDetail.setMerchantSettlement(merchantSettlement);
            deductionDetail.setBusinessDebitNote(businessDebitNote);
            deductionDetail.setDeductionDate(new Date());
            deductionDetail.setPreviousPrincipal(merchantBusinessDebitItem.getPriceDebit() - merchantBusinessDebitItem.getPrincipalRepaid());
            deductionDetail.setRepaymentAmount(merchantBusinessDebitItem.getCurrentAmount());
            deductionDetail.setCurrentPrincipal(deductionDetail.getPreviousPrincipal() - deductionDetail.getRepaymentAmount());

            businessDebitNote.setPrincipalRepaid(businessDebitNote.getPrincipalRepaid() + merchantBusinessDebitItem.getCurrentAmount());
            businessDebitNote.setPrepaidPrincipal(businessDebitNote.getPrepaidPrincipal()-merchantBusinessDebitItem.getCurrentAmount());
            businessDebitNote.setUnpaidPrincipal(businessDebitNote.getPriceDebit() - businessDebitNote.getPrincipalRepaid());
            businessDebitNote.setCapitalBalance(businessDebitNote.getPriceDebit() - businessDebitNote.getPrincipalRepaid());
            businessDebitNote.getDeductionDetails().add(deductionDetail);
            businessDebitNote.setUnDeductedLoanAmount(businessDebitNote.getUnDeductedLoanAmount() - merchantBusinessDebitItem.getCurrentAmount());
            businessDebitNote.setState(businessDebitNote.getUnpaidPrincipal() == 0 ? "paidOff" : "partialDeduction");
            businessDebitNoteRepository.saveAndFlush(businessDebitNote);

        });

    }

    /**
     * 获取对账数据
     *
     * @param request
     * @return
     */
    public MerchantSettlement generateReconciliationData(SimpleRequest request) throws ParseException {
        //获取请求参数
        JSONObject requestJO = request.getJO();

        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date reconcileBeginDate = dateFormat.parse(requestJO.getString("reconcileBeginDate"));
        Date reconcileEndDate = dateFormat.parse(requestJO.getString("reconcileEndDate"));

        String merchantId = requestJO.getString("merchantId");
        return getMerchantSettlement(reconcileBeginDate, reconcileEndDate, merchantId);
    }

    /**
     * 生成对账单
     *
     * @param reconcileBeginDate
     * @param reconcileEndDate
     * @param merchantId
     * @return
     */
    private MerchantSettlement getMerchantSettlement(Date reconcileBeginDate, Date reconcileEndDate, String merchantId) {
        //获取有效的政策
        SpringManager.getBean(AccountSettlementService.class).checkPolicy(merchantId, reconcileBeginDate, getAddDay(reconcileEndDate));
        //获取上期对账数据
        MerchantSettlement previousMerchantSettlement = getThePreviousMerchantSettlement(merchantId, reconcileBeginDate);

        //生成对账单
        MerchantSettlement merchantSettlement = new MerchantSettlement();

        merchantSettlement.setReconcileBeginDate(reconcileBeginDate);
        merchantSettlement.setReconcileEndDate(reconcileEndDate);

        //获取商户营业额数据
        List<Map> businessTurnoverData = merchantSettlementDao.getSumBusinessTurnoverData(merchantId, reconcileBeginDate, reconcileEndDate);
        String sale_money = Objects.nonNull(businessTurnoverData.get(0).get("SALE_MONEY")) ? String.valueOf(businessTurnoverData.get(0).get("SALE_MONEY")) : null;
        String cross_company_pay = Objects.nonNull(businessTurnoverData.get(0).get("CROSS_COMPANY_PAY")) ? String.valueOf(businessTurnoverData.get(0).get("CROSS_COMPANY_PAY")) : null;
        String cross_company_income = Objects.nonNull(businessTurnoverData.get(0).get("CROSS_COMPANY_INCOME")) ? String.valueOf(businessTurnoverData.get(0).get("CROSS_COMPANY_INCOME")) : null;
        String accounts_receivable_out = Objects.nonNull(businessTurnoverData.get(0).get("ACCOUNTS_RECEIVABLEOUT")) ? String.valueOf(businessTurnoverData.get(0).get("ACCOUNTS_RECEIVABLEOUT")) : null;

        double businessMoney = businessTurnoverData.isEmpty() ? 0 : sale_money == null ? 0 : Double.parseDouble(sale_money);
        double crossCompanyIncome = businessTurnoverData.isEmpty() ? 0 : cross_company_income == null ? 0 : Double.parseDouble(cross_company_income);
        double crossCompanyPay = businessTurnoverData.isEmpty() ? 0 : cross_company_pay == null ? 0 : Double.parseDouble(cross_company_pay);
        double accountsReceivable = businessTurnoverData.isEmpty() ? 0 : accounts_receivable_out == null ? 0 : Double.parseDouble(accounts_receivable_out);
        merchantSettlement.setBusinessMoney(businessMoney);
        merchantSettlement.setAccountsReceivable(accountsReceivable);
        merchantSettlement.setAdjustedTurnoverMoney(merchantSettlement.getBusinessMoney());
        //常备库存金额
        merchantSettlement.setInventoryMoney(getStandingInventoryAmount(merchantId));
        //获取会员跨公司消费收入
//        getCrossCompanyIncome(merchantId, merchantSettlement);
        merchantSettlement.setCrossCompanyIncome(crossCompanyIncome);
        //获取会员跨公司消费支出
//        getCrossCompanyPay(merchantId, merchantSettlement);
        merchantSettlement.setCrossCompanyPay(crossCompanyPay);
        //平台服务费
        merchantSettlement.setPlatformServiceFee(merchantSettlementDao.getBusinessTurnoverData(merchantId, reconcileBeginDate, reconcileEndDate).stream().map(data->  (Double.parseDouble(data.get("INCOME").toString())*getBean(FeeRateService.class).getPlatformRules(merchantId, (Date) data.get("DATE_OF_STATISTICS")))).reduce(Arith::add).orElse(0.0));

        //平台服务费减免金额
        merchantSettlement.setPlatformServiceFeeReduced(Arith.round(merchantSettlementDao.findSumFeeReducedDetail(merchantId, reconcileBeginDate, getAddDay(reconcileEndDate)),2));

        //获取待扣收费用单
        getMerchantExpense(merchantId, merchantSettlement);
        //获取待扣借支单
        getMerchantBusinessDebitItem(merchantId, merchantSettlement);
        //获取上期成本
        Map<String, CostSummary> costSummaryMap = previousMerchantSettlement == null ? new HashMap<>() : previousMerchantSettlement.getCostSummaries().stream().collect(Collectors.toMap(costSummary -> costSummary.getCostSummaryType().getId(), costSummary -> costSummary, (k1, k2) -> k1));

        //委托定损成本服务费
        merchantSettlement.setLossAssessmentCostFee(merchantSettlementDao.getLossAssessmentCostData(merchantId, reconcileBeginDate, reconcileEndDate).stream().map(data->  (Double.parseDouble(data.get("TAX_COST_PRICE").toString())*getBean(FeeRateService.class).getPlatformRules(merchantId, (Date) data.get("CREATE_DATE")))).reduce(Arith::add).orElse(0.0));
        //平台服务费-委托定损成本服务费
        merchantSettlement.setPlatformServiceFee(merchantSettlement.getPlatformServiceFee()-merchantSettlement.getLossAssessmentCostFee());
        merchantSettlement.setAdjustedPlatformServiceFee(merchantSettlement.getPlatformServiceFee());

        //获取成本
        List<CostSummary> costSummaries = new ArrayList<>(6);
        //获取成本项目枚举
        List<Enumeration> enumerations = SpringManager.getBean(EnumerationRepository.class).findByTypeAndValid("costSummary");
        //遍历成本项目 汇总成本
        addCost(reconcileBeginDate, reconcileEndDate, merchantId, merchantSettlement, costSummaryMap, costSummaries, enumerations);
        merchantSettlement.setCostSummaries(costSummaries);
        merchantSettlement.computeAmt();
        return merchantSettlement;
    }

    /**
     * 汇总成本
     *
     * @param reconcileBeginDate
     * @param reconcileEndDate
     * @param merchantId
     * @param merchantSettlement
     * @param costSummaryMap
     * @param costSummaries
     * @param enumerations
     */
    private void addCost(Date reconcileBeginDate, Date reconcileEndDate, String merchantId, MerchantSettlement merchantSettlement, Map<String, CostSummary> costSummaryMap, List<CostSummary> costSummaries, List<Enumeration> enumerations) {
        enumerations.forEach(enumeration -> {
            CostSummary costSummary = new CostSummary();
            //营业成本
            if (Objects.equals("operatingCosts", enumeration.getId())) {
                //获取上期未扣收
                double remainingDeductibleBalance = costSummaryMap.isEmpty() ? 0 : costSummaryMap.get("operatingCosts").getRemainingDeductibleBalance();
                //获取本期应扣收
                double total = getTheTotal(getCurrentConsumeVoucher(merchantId, reconcileBeginDate, reconcileEndDate), "priceTotal") +
                        getTheTotal(getCurrentPurchaseVoucher(merchantId, reconcileBeginDate, reconcileEndDate), "priceTotal") + remainingDeductibleBalance;
                costSummary.setCurrentPeriodShouldDeducted(Arith.round(total, 2));
                costSummary.setCostSummaryType(enumeration);
                costSummary.setPreviousNotDeducted(remainingDeductibleBalance);
                costSummary.setCurrentPeriodActualDeducted(costSummary.getCurrentPeriodShouldDeducted());
                costSummary.setFormId("voucher.costs");
                costSummary.setRemainingDeductibleBalance(costSummary.getCurrentPeriodShouldDeducted() - costSummary.getCurrentPeriodActualDeducted());
            }
            //营业款借支
            if (Objects.equals("businessDebit", enumeration.getId())) {
                //获取上期未扣收
                double remainingDeductibleBalance = costSummaryMap.isEmpty() ? 0 : costSummaryMap.get("businessDebit").getRemainingDeductibleBalance();
                //获取本期应扣收
                costSummary.setCurrentPeriodShouldDeducted(merchantSettlement.getMerchantBusinessDebitItems().stream().mapToDouble(MerchantBusinessDebitItem::getCurrentAmount).sum());
                costSummary.setCostSummaryType(enumeration);
                costSummary.setPreviousNotDeducted(remainingDeductibleBalance);
                costSummary.setCurrentPeriodActualDeducted(costSummary.getCurrentPeriodShouldDeducted());
                costSummary.setFormId("business.form");
                costSummary.setRemainingDeductibleBalance(costSummary.getCurrentPeriodShouldDeducted() - costSummary.getCurrentPeriodActualDeducted());
            }
            //平台费用
            if (Objects.equals("platformFee", enumeration.getId())) {
                //获取上期未扣收
                double remainingDeductibleBalance = costSummaryMap.isEmpty() ? 0 : costSummaryMap.get("platformFee").getRemainingDeductibleBalance();
                //获取本期应扣收
                costSummary.setCurrentPeriodShouldDeducted(merchantSettlement.getMerchantExpenseItems().stream().mapToDouble(MerchantExpenseItem::getCurrentAmount).sum());
                costSummary.setCostSummaryType(enumeration);
                costSummary.setPreviousNotDeducted(remainingDeductibleBalance);
                costSummary.setCurrentPeriodActualDeducted(costSummary.getCurrentPeriodShouldDeducted());
                costSummary.setFormId("expense.form");
                costSummary.setRemainingDeductibleBalance(costSummary.getCurrentPeriodShouldDeducted() - costSummary.getCurrentPeriodActualDeducted());
            }
            //供应链管理费
            if (Objects.equals("supplyChainFee", enumeration.getId())) {
                //获取上期未扣收
                double remainingDeductibleBalance = costSummaryMap.isEmpty() ? 0 : costSummaryMap.get("supplyChainFee").getRemainingDeductibleBalance();
                //获取本期应扣收
                costSummary.setCurrentPeriodShouldDeducted(Arith.round(merchantSettlementDao.findCurrentPeriodShouldDeducted(merchantId, reconcileBeginDate, getAddDay(reconcileEndDate)) + remainingDeductibleBalance, 2));
                costSummary.setCostSummaryType(enumeration);
                costSummary.setPreviousNotDeducted(Arith.round(remainingDeductibleBalance, 2));
                costSummary.setCurrentPeriodActualDeducted(costSummary.getCurrentPeriodShouldDeducted());
                costSummary.setFormId("supplier.management.fee.form");
                costSummary.setRemainingDeductibleBalance(costSummary.getCurrentPeriodShouldDeducted() - costSummary.getCurrentPeriodActualDeducted());
            }
            //天猫平台费
            if (Objects.equals("tmallPlatformFee", enumeration.getId())) {
                //获取上期未扣收
                double remainingDeductibleBalance = costSummaryMap.isEmpty() ? 0 : Objects.isNull(costSummaryMap.get("tmallPlatformFee")) ? 0 : costSummaryMap.get("tmallPlatformFee").getRemainingDeductibleBalance();
                double sumPlatformFeeByChannel = merchantSettlementDao.findSumPlatformFeeByChannel(merchantId,"100", reconcileBeginDate, getAddDay(reconcileEndDate));
                //获取本期应扣收
                costSummary.setCurrentPeriodShouldDeducted(Arith.round(sumPlatformFeeByChannel + remainingDeductibleBalance, 2));
                costSummary.setCostSummaryType(enumeration);
                costSummary.setPreviousNotDeducted(Arith.round(remainingDeductibleBalance, 2));
                costSummary.setCurrentPeriodActualDeducted(costSummary.getCurrentPeriodShouldDeducted());
                costSummary.setFormId("Tmall.platform.fee");
                costSummary.setRemainingDeductibleBalance(costSummary.getCurrentPeriodShouldDeducted() - costSummary.getCurrentPeriodActualDeducted());
            }
            //车行易平台佣金
            if (Objects.equals("CXYFee", enumeration.getId())) {
                //获取上期未扣收
                double remainingDeductibleBalance = costSummaryMap.isEmpty() ? 0 : Objects.isNull(costSummaryMap.get("CXYFee")) ? 0 : costSummaryMap.get("CXYFee").getRemainingDeductibleBalance();
                double sumPlatformFeeByChannel= merchantSettlementDao.findSumPlatformFeeByChannel(merchantId,"75", reconcileBeginDate, getAddDay(reconcileEndDate));
                //获取本期应扣收
                costSummary.setCurrentPeriodShouldDeducted(Arith.round(sumPlatformFeeByChannel + remainingDeductibleBalance, 2));
                costSummary.setCostSummaryType(enumeration);
                costSummary.setPreviousNotDeducted(Arith.round(remainingDeductibleBalance, 2));
                costSummary.setCurrentPeriodActualDeducted(costSummary.getCurrentPeriodShouldDeducted());
                costSummary.setFormId("Tmall.platform.fee");
                costSummary.setRemainingDeductibleBalance(costSummary.getCurrentPeriodShouldDeducted() - costSummary.getCurrentPeriodActualDeducted());
            }
            //定损管理费
            if (Objects.equals("quotationExpense", enumeration.getId())) {
                //获取上期未扣收
                double remainingDeductibleBalance = costSummaryMap.isEmpty() ? 0 : Objects.isNull(costSummaryMap.get("quotationExpense")) ? 0 : costSummaryMap.get("quotationExpense").getRemainingDeductibleBalance();
                double sumQuotationExpense = settleExpenseRepository.findAmountByTypeAndTenant(merchantId, reconcileBeginDate, getAddDay(reconcileEndDate));
                //获取本期应扣收
                costSummary.setCurrentPeriodShouldDeducted(Arith.round(sumQuotationExpense + remainingDeductibleBalance, 2));
                costSummary.setCostSummaryType(enumeration);
                costSummary.setPreviousNotDeducted(Arith.round(remainingDeductibleBalance, 2));
                costSummary.setCurrentPeriodActualDeducted(costSummary.getCurrentPeriodShouldDeducted());
                costSummary.setFormId("quotation.expense.fee");
                costSummary.setRemainingDeductibleBalance(costSummary.getCurrentPeriodShouldDeducted() - costSummary.getCurrentPeriodActualDeducted());
            }
//            //采购变价费用
//            if (Objects.equals("priceChangeFee", enumeration.getId())) {
//                //获取上期未扣收
//                double remainingDeductibleBalance = costSummaryMap.isEmpty() ? 0 : Objects.isNull(costSummaryMap.get("priceChangeFee")) ? 0 : costSummaryMap.get("priceChangeFee").getRemainingDeductibleBalance();
//                double sum = getPriceChangeInvoice(merchantId, reconcileBeginDate, getAddDay(reconcileEndDate)).stream().mapToDouble(Invoice::getAmtTotal).sum();
//                //获取本期应扣收
//                costSummary.setCurrentPeriodShouldDeducted(Arith.round(sum, 2));
//                costSummary.setCostSummaryType(enumeration);
//                costSummary.setPreviousNotDeducted(Arith.round(remainingDeductibleBalance, 2));
//                costSummary.setCurrentPeriodActualDeducted(costSummary.getPreviousNotDeducted() + costSummary.getCurrentPeriodShouldDeducted());
//                costSummary.setFormId("merchant.settle.findPriceChangeInvoice");
//                costSummary.setRemainingDeductibleBalance(costSummary.getCurrentPeriodShouldDeducted() - costSummary.getCurrentPeriodActualDeducted());
//            }

            //车险销售管理费
            if (Objects.equals("insuranceFee", enumeration.getId())) {
                //获取上期未扣收
                double remainingDeductibleBalance = costSummaryMap.isEmpty() ? 0 : Objects.isNull(costSummaryMap.get("insuranceFee")) ? 0 : costSummaryMap.get("insuranceFee").getRemainingDeductibleBalance();
                double sum = insuranceOrderRepository.findByCompany(merchantId, reconcileBeginDate, getAddDay(reconcileEndDate)).stream().mapToDouble(InsuranceOrder::getInsuranceManagementFee).sum();
                //获取本期应扣收
                costSummary.setCurrentPeriodShouldDeducted(Arith.round(sum + remainingDeductibleBalance, 2));
                costSummary.setCostSummaryType(enumeration);
                costSummary.setPreviousNotDeducted(Arith.round(remainingDeductibleBalance, 2));
                costSummary.setCurrentPeriodActualDeducted(costSummary.getCurrentPeriodShouldDeducted());
                costSummary.setFormId("merchant.settle.findInsuranceManagementFee");
                costSummary.setRemainingDeductibleBalance(costSummary.getCurrentPeriodShouldDeducted() - costSummary.getCurrentPeriodActualDeducted());
            }

            costSummaries.add(costSummary);
        });
    }


    /**
     * 获取会员跨公司消费收入
     *
     * @param merchantSettlement
     */
    private void getCrossCompanyIncome(String merchantId, MerchantSettlement merchantSettlement) {
        merchantSettlement.setCrossCompanyIncome(merchantSettlementDao.findCrossCompanyIncomeSum(merchantId, merchantSettlement.getReconcileBeginDate(), getAddDay(merchantSettlement.getReconcileEndDate())));
    }

    /**
     * 获取会员跨公司消费支出
     *
     * @param merchantSettlement
     */
    private void getCrossCompanyPay(String merchantId, MerchantSettlement merchantSettlement) {
        merchantSettlement.setCrossCompanyPay(merchantSettlementDao.findCrossCompanyPaySum(merchantId, merchantSettlement.getReconcileBeginDate(), getAddDay(merchantSettlement.getReconcileEndDate())));
    }

    /**
     * 获取该商户目前所有待扣收费用单
     *
     * @param merchantId
     * @return
     */
    public void getMerchantExpense(String merchantId, MerchantSettlement merchantSettlement) {
        //获取截止本期为止的待扣收费用单
        List<ExpenseItem> expenseItems = expenseItemRepository.findAllByExpenseCompany(merchantId);
        List<MerchantExpenseItem> merchantExpenseItems = new ArrayList<>(expenseItems.size());
        expenseItems.forEach(expenseItem -> {
            MerchantExpenseItem merchantExpenseItem = new MerchantExpenseItem();
            merchantExpenseItem.setExpenseItem(expenseItem);
            merchantExpenseItem.setCurrentAmount(expenseItem.getAmount() - expenseItem.getAmountDeducted()- expenseItem.getWithholdingAmount());
            //检查0元的费用是否已被对账
            if (expenseItem.getAmount()==0){
                List<MerchantExpenseItem> itemList = SpringManager.getBean(MerchantExpenseItemRepository.class).findAll(JpaDsl.toCriteriaByEq("expenseItem.id", expenseItem.getId()));
                if (itemList.isEmpty()){
                    merchantExpenseItems.add(merchantExpenseItem);
                }
            }else {
                merchantExpenseItems.add(merchantExpenseItem);
            }
        });
        merchantSettlement.setMerchantExpenseItems(merchantExpenseItems);
    }

    /**
     * 获取该商户目前所有待扣借支单单
     *
     * @param merchantId
     * @return
     */
    public void getMerchantBusinessDebitItem(String merchantId, MerchantSettlement merchantSettlement) {
        //获取截止本期为止的待扣收费用单
        List<BusinessDebitNote> businessDebitNote = businessDebitNoteRepository.findAllByFnCustomerId(merchantId,merchantSettlement.getReconcileEndDate());
        List<MerchantBusinessDebitItem> merchantBusinessDebitItems = new ArrayList<>(businessDebitNote.size());
        businessDebitNote.forEach(debitNote -> {
            MerchantBusinessDebitItem merchantBusinessDebitItem = new MerchantBusinessDebitItem();
            merchantBusinessDebitItem.setBusinessDebitNote(debitNote);
            merchantBusinessDebitItem.setCurrentAmount(debitNote.getUnpaidPrincipal()-debitNote.getPrepaidPrincipal());
            merchantBusinessDebitItems.add(merchantBusinessDebitItem);
        });
        merchantSettlement.setMerchantBusinessDebitItems(merchantBusinessDebitItems);
    }


    /**
     * 获取当期寄售消耗凭证
     *
     * @param merchantId
     * @param reconcileBeginDate
     * @param reconcileEndDate
     * @return
     */
    public List<Map> getCurrentConsumeVoucher(String merchantId, Date reconcileBeginDate, Date reconcileEndDate) {
        return voucherRepository.findByCompanyAndVoucherType(merchantId, VoucherType.SUPPLIER_CONSUME, InventoryMode.IM_CONSIGN, reconcileBeginDate, getAddDay(reconcileEndDate));
    }

    /**
     * 获取当期采购凭证
     *
     * @param merchantId
     * @param reconcileBeginDate
     * @param reconcileEndDate
     * @return
     */
    public List<Map> getCurrentPurchaseVoucher(String merchantId, Date reconcileBeginDate, Date reconcileEndDate) {
        return voucherRepository.findByCompanyAndVoucherType(merchantId, VoucherType.SUPPLIER_PURCHASE, InventoryMode.IM_OWN, reconcileBeginDate, getAddDay(reconcileEndDate));
    }

    /**
     * 获取上期商户对账单
     *
     * @param merchantId
     * @param reconcileBeginDate
     * @return
     */
    public MerchantSettlement getThePreviousMerchantSettlement(String merchantId, Date reconcileBeginDate) {
        //业务场景为 上一次对账结束时间+1天即为此次对账开始时间
        List<MerchantSettlement> settlement =  merchantSettlementRepository.findByMaxReconcileEndDate(merchantId);
        if(settlement.size() == 0) return null;
        if(settlement.size() > 1) throw new RuntimeException(String.format("获取上期对账单异常！存在多张上期对账单！请检查数据!"));

        Date previousReconcileEndDate = DateUtil.add(reconcileBeginDate, Calendar.DAY_OF_MONTH, -1);
        if (previousReconcileEndDate.compareTo(settlement.get(0).getReconcileEndDate()) != 0) {
            throw new RuntimeException(String.format("商户[%s]此次对账开始日期有误！应为上次对账日期[%s]+1天", merchantId, DateUtil.format(settlement.get(0).getReconcileEndDate(), "yyyy-MM-dd")));
        }

        return settlement.get(0);
    }

    /**
     * 获取常备库存金额
     *
     * @param merchantId
     * @return
     */
    public double getStandingInventoryAmount(String merchantId) {
        return SpringManager.getBean(InventoryBatchRepository.class).findStandingInventoryAmount(merchantId);
    }


    /**
     * 监听凭证 计算供应链管理费
     * 经销商品的采购入库、返厂时生成的采购凭证
     * 代销库存销售时生成的寄售消耗凭证
     * 采购变价单待定
     *
     * @param voucher
     */
    public Voucher calculateCost(Voucher voucher) {
        //获取接入商
        AccessProvider accessProvider = SpringManager.getBean(AccessProviderRepository.class).findByCompany(voucher.getCompany().getId());
        Optional.ofNullable(accessProvider).orElseThrow(() -> new RuntimeException(String.format("公司[%s]无接入商", voucher.getCompany().getId())));

        PartyRole partner = SpringManager.getBean(PartyRoleRepository.class).findOne(
                JpaDsl.toCriteriaByEq(
                        "party.id", voucher.getPartner().getParty().getId(),
                        "role.id", "Company"
                )
        ).orElse(null);
        AccessProvider partnerAccessProvider = null;
        if (partner != null) {
            partnerAccessProvider = SpringManager.getBean(AccessProviderRepository.class).findByCompany(partner.getId());
        }

        if (!Objects.equals(accessProvider.getId(), Objects.isNull(partnerAccessProvider) ? null : partnerAccessProvider.getId())
                && !Objects.equals(Objects.isNull(voucher.getScene()) ? null : voucher.getScene().getId(), "PO002")
                && !Objects.equals(Objects.isNull(voucher.getScene()) ? null : voucher.getScene().getId(), "PR004")) {
            //代销库存销售时生成的寄售消耗凭证
            if (voucher.getVoucherType().equals(VoucherType.SUPPLIER_CONSUME) && voucher.getInventoryMode().equals(InventoryMode.IM_CONSIGN) && !Objects.equals(voucher.getPartner().getId(), "A00000")) {
                voucher.getVoucherItems().forEach(voucherItem -> {
                    double fee = getBean(FeeRateService.class).getSupplyChainManagementFee(voucher.getCompany().getId(), voucherItem.getProduct().getClassify().getId(), voucher.getPartner().getId());
                    voucherItem.setSupplyChainManagementFee(voucherItem.getPriceTotal() * fee);
                    voucherItem.setFeeRate(fee);

                });
            }
            //经销商品的采购入库、返厂时生成的采购凭证
            if (voucher.getVoucherType().equals(VoucherType.SUPPLIER_PURCHASE) && voucher.getInventoryMode().equals(InventoryMode.IM_OWN)) {
                voucher.getVoucherItems().forEach(voucherItem -> {
                    double fee = getBean(FeeRateService.class).getSupplyChainManagementFee(voucher.getCompany().getId(), voucherItem.getProduct().getClassify().getId(), voucher.getPartner().getId());
                    voucherItem.setSupplyChainManagementFee(voucherItem.getPriceTotal() * fee);
                    voucherItem.setFeeRate(fee);
                });
            }

        }

        //合计供应链管理费
        voucher.setSupplyChainManagementFee(voucher.getVoucherItems().stream().mapToDouble(VoucherItem::getSupplyChainManagementFee).sum());
        return voucherRepository.save(voucher);
    }


    /**checkReconciliationDate
     * 获取采购变价单账单
     *
     * @param merchantId
     * @param reconcileBeginDate
     * @param reconcileEndDate
     * @return
     */
    public List<Invoice> getPriceChangeInvoice(String merchantId, Date reconcileBeginDate, Date reconcileEndDate) {
        return invoiceRepository.findAllByCompanyAndOriginBusinessType(merchantId, "PriceChange", reconcileBeginDate, reconcileEndDate);

    }

    /**
     * 日结
     *
     * @param request
     */
    public void dayKnot(SimpleRequest request) {
        //获取有效的政策
        Date taskDate = DateUtil.dateToDate(request.getJO().getDate("taskDate"), DateUtil.SHOW_DATE_FORMAT);
        List<PartnerCheck> partnerChecks = partnerCheckRepository.findAllByState(taskDate, "approve");
        if (!partnerChecks.isEmpty()) {
            partnerChecks.forEach(partnerCheck -> {
                //结算周期不能为空
                if (Objects.isNull(partnerCheck.getPeriodType())) {
                    return;
                }
                Map payload = MapUtil.mapper("id", partnerCheck.getId(), "taskDate", DateUtil.format(taskDate, DateUtil.SHOW_DATE_FORMAT));
                SpringManager.getBean(OutboxSubscriberService.class).commonSendRequest("merchant.partnerCheck.handling", partnerCheck.getId(), payload);
            });
        }
    }

    @OutboxSubscriber(id="merchant.partnerCheck.handling", name="结算政策执行")
    public void handling(OutboxPayloadWrapper outboxPayloadWrapper) {
        JSONObject payload = JSON.parseObject(outboxPayloadWrapper.getPayload()) ;
        String id = payload.getString("id");
        Date taskDate = DateUtil.parse(payload.getString("id"), DateUtil.SHOW_DATE_FORMAT);
        try {
            //生成费用单 (重新查询是因为防止懒加载异常)
            saveExpense(partnerCheckRepository.findOne(id), taskDate);
        } catch (Exception e) {
          throw new RuntimeException(e);
        }
    }

    @Autowired
    private TransactionTemplate transactionTemplate;

    public void execute(Callback callback) {
        transactionTemplate.execute(status -> {
            try {
                callback.execute();
                return null;
            } catch (Exception e) {
                status.isRollbackOnly();
                throw new RuntimeException(e.getMessage());
            }
        });
    }

    @FunctionalInterface
    public interface Callback {
        void execute();
    }


    /**
     * 生成对账单
     *
     * @param partnerCheck
     * @param lastReconciliationDate
     * @param merchantId
     * @param merchantSettlement
     */
    private void saveMerchantSettlement(PartnerCheck partnerCheck, Date lastReconciliationDate, String merchantId, MerchantSettlement merchantSettlement) {
        //获取对账日期
        Date reconciliationDate = getSettlementDate(lastReconciliationDate, partnerCheck.getPeriodType().getCode());
        //判断是否达到对账日期
        if (checkReconciliationDate(reconciliationDate)) {
            if (Objects.isNull(merchantSettlement)) {
                partnerCheck.setLastCheckDate(reconciliationDate);
            }
            Date date = DateUtil.ULocalDateToDate(LocalDate.now());
            //生成对账单
            MerchantSettlement settlement = getMerchantSettlement(reconciliationDate, date, merchantId);
            settlement.setMerchant(partnerCheck.getFnCustomer());
            settlement.setState("sent");
            settlement.setReconcileDate(date);
            processingExpenseBill(settlement, 1);
            merchantSettlementRepository.saveAndFlush(settlement);
        }
    }

    /**
     * 生成费用单
     * 注:供应链管理费和平台服务费不根据政策生成 目前政策生成的费用单只有固定金额   需求改变的话此处取数需修改
     *
     * @param partnerCheck
     */
    private void saveExpense(PartnerCheck partnerCheck,Date nowDate) {
        //生成费用单
        List<ExpenseItem> expenseItemList = new ArrayList<>();
        partnerCheck.getPartnerCheckItems().forEach(partnerCheckItem -> {
            //计算基数只能为固定金额
            if ("fixedAmount".equals(partnerCheckItem.getCostType().getId())) {
                //获取默认开始时间
                Date lastReconciliationDate = getDefaultStartDate();
                //获取首次结算日期
                //Date lastReconciliationDate = DateUtil.add(partnerCheck.getFirstCheckDate(), Calendar.DAY_OF_MONTH, -1);
                //通过结算政策号和商户获取最后生成日期
//                Date lastDateBySettlePolicy = expenseItemRepository.findLastDateBySettlePolicy(partnerCheckItem.getExpenseType().getId(), partnerCheck.getFnCustomer().getId(), partnerCheck.getId());
                //通过费用类型和商户获取最后生成日期
                Date lastDateByExpenseTypeAndCompany = expenseItemRepository.findLastDateByExpenseTypeAndCompany(partnerCheckItem.getExpenseType().getId(), partnerCheck.getFnCustomer().getId());
                if (Objects.nonNull(lastDateByExpenseTypeAndCompany)) {
                    lastReconciliationDate = lastDateByExpenseTypeAndCompany;
                }
                //获取本次生成日期
                Date reconciliationDate = getReconciliationDate(lastReconciliationDate, partnerCheckItem.getCaclType().getCode());

                //执行日期不在费用起止则不生成费用明细
                boolean start = true;
                boolean end = true;
                if (!ObjectUtils.isEmpty(partnerCheckItem.getPeriodStart()) && !ObjectUtils.isEmpty(partnerCheckItem.getPeriodEnd())){
                    start = DateUtil.belongCalendar(lastReconciliationDate,
                            DateUtil.dateToDate(partnerCheckItem.getPeriodStart(), DateUtil.SHOW_DATE_FORMAT),
                            DateUtil.dateToDate(partnerCheckItem.getPeriodEnd(), DateUtil.SHOW_DATE_FORMAT));

                    end = DateUtil.belongCalendar(reconciliationDate,
                            DateUtil.dateToDate(partnerCheckItem.getPeriodStart(), DateUtil.SHOW_DATE_FORMAT),
                            DateUtil.dateToDate(partnerCheckItem.getPeriodEnd(), DateUtil.SHOW_DATE_FORMAT));
                }
                if (!start && !end){
                    return;
                }

                //判断是否达到生成日期
                if(reconciliationDate.equals(nowDate)) {
                    //只计算固定金额
                    ExpenseItem expenseItem = new ExpenseItem();
                    expenseItem.setAmount(partnerCheckItem.getRateOne());
                    expenseItem.setExpenseType(partnerCheckItem.getExpenseType());
                    expenseItem.setCalculateDate(new Date());
                    expenseItem.setPeriodStart(getAddDay(lastReconciliationDate));
                    expenseItem.setPeriodEnd(reconciliationDate);
                    expenseItem.setCompany(partnerCheck.getFnCustomer());
                    expenseItem.setSettlePolicy(partnerCheck.getId());
                    expenseItemList.add(expenseItem);
                }
            }


        });
        if (!expenseItemList.isEmpty()) {
            Expense expense = new Expense();
            FnContract fnContract = fnContractRepository.findCompany(partnerCheck.getFnCustomer().getId(),new Date());
            expense.setCompany(fnContract.getCompany());
            expense.setAmtTotal(expenseItemList.stream().mapToDouble(ExpenseItem::getAmount).sum());
            expense.setCreator("system");
            expense.setApproveId(partyRoleRepository.findOne("system"));
            expense.setState("approve");
            expense.setApproveDate(new Date());
            expense.setRemark(String.format("日结产生！赋能商户政策[%s]", partnerCheck.getId()));
            expense.setExpenseItems(expenseItemList);
            expenseRepository.saveAndFlush(expense);
            expenseService.createBills(expense);//生产费用账单
        }
    }

    /**
     * 获取费用明细默认开始时间
     * @return
     */
    private Date getDefaultStartDate(){
        Date startDate = null;
        Date executeDate1 = DateUtil.getCustomDate(0, 1, 0, 0, 0);
        if (DateUtil.dateCompare(new Date(),executeDate1) == 0){
            //当前时间为1号则执行的数据是上个月15-最后一天，所以开始日期为15号
            startDate = DateUtil.getCustomDate(0, 15, 0, 0, 0);
        }else {
            //16号执行的是1-15号数据，所以开始日期为1号
            startDate = DateUtil.getCustomDate(0, 1, 0, 0, 0);
            startDate = DateUtil.add(startDate, Calendar.DAY_OF_MONTH, -1);
        }
        return startDate;
    }

    /**
     * 计算总数
     *
     * @param list
     * @param value
     * @return
     */
    public double getTheTotal(List list, String value) {
        return list.stream().mapToDouble(map -> (double) ((Map) map).get(value)).sum();
    }

    /**
     * 检查对账日期
     *
     * @param reconciliationDate
     * @return
     */
    private boolean checkReconciliationDate(Date reconciliationDate) {
        //获取当前日期
        LocalDate localDate = LocalDate.now();
        return DateUtil.UDateToLocalDate(reconciliationDate).equals(localDate);

    }

    /**
     * 获取日期+1
     *
     * @param date
     * @return
     */
    public static Date getAddDay(Date date) {
        return DateUtil.add(date, Calendar.DAY_OF_MONTH, 1);
    }


    /**
     * 获取下次对账日期（费用）
     *
     * @param lastReconciliationDate
     * @param code
     * @return
     */
    private Date getReconciliationDate(Date lastReconciliationDate, String code) {
        LocalDate lastDate = DateUtil.UDateToLocalDate(new Date(lastReconciliationDate.getTime()));
        if ("perHalfMonth".equals(code)) {
            //半月结增加15天 下半月结直接取当月最后一天
            if (lastDate.getDayOfMonth() == 15) {
                lastDate = lastDate.with(TemporalAdjusters.lastDayOfMonth());
            } else {
                lastDate = lastDate.plusDays(15);
            }
        } else if ("perMonth".equals(code)) {
            //月结增加1月
            lastDate = lastDate.plusMonths(1).with(TemporalAdjusters.lastDayOfMonth());
        } else if ("perQuarter".equals(code)) {
            //季度结增加3月
            lastDate = lastDate.plusMonths(3);
        } else if ("perHalfYear".equals(code)) {
            //半年结增加6月
            lastDate = lastDate.plusMonths(6);
        } else if ("perYear".equals(code)) {
            //年结增加1年
            lastDate = lastDate.plusYears(1);
        } else if ("perWeek".equals(code)) {
            //周结增加一周
            lastDate = lastDate.plusWeeks(1);
        }
        return DateUtil.ULocalDateToDate(lastDate);
    }

    /**
     * 获取下次对账日期（政策）
     *
     * @param lastReconciliationDate
     * @param code
     * @return
     */
    private Date getSettlementDate(Date lastReconciliationDate, String code) {
        LocalDate lastDate = DateUtil.UDateToLocalDate(new Date(lastReconciliationDate.getTime()));
        if ("halfMonth".equals(code)) {
            //半月结增加15天
            lastDate = lastDate.plusDays(15);
        } else if ("month".equals(code)) {
            //月结增加1月
            lastDate = lastDate.plusMonths(1);
        } else if ("week".equals(code)) {
            //周结增加一周
            lastDate = lastDate.plusWeeks(1);
        }
        return DateUtil.ULocalDateToDate(lastDate);
    }

    /**
     * 获取成本
     *
     * @param request
     * @return
     * @throws ParseException
     */
    public JSONObject findVoucherCosts(SimpleRequest request) throws ParseException {
        JSONObject parameters = parseParameters(request);
        JSONObject object = new JSONObject();
        //取结果集
        List<Map> resultList = merchantSettlementDao.findVoucherCosts(parameters.getString("merchantId"), parameters.getDate("reconcileBeginDate"), parameters.getDate("reconcileEndDate"), parameters.getInteger("page"), parameters.getInteger("size"));
        Object costsCount = merchantSettlementDao.findVoucherCostsCount(parameters.getString("merchantId"), parameters.getDate("reconcileBeginDate"), parameters.getDate("reconcileEndDate"));
        object.put("content", resultList);
        object.put("total", costsCount);
        object.put("pages", costsCount);
        return object;
    }

    /**
     * 查询应收账款(外)明细
     *
     * @param request
     * @return
     */
    public JSONObject findAccountsReceivable(SimpleRequest request) throws ParseException {
        JSONObject requestJO = request.getJO();
        int page = 0;
        int size = 50;
        if (requestJO.containsKey("data")) {
            requestJO = requestJO.getJSONObject("data");
            page = (int) request.getJO().get("page");
            size = (int) request.getJO().get("size");
        }
        JSONObject object = new JSONObject();
        String merchantId = requestJO.getString("merchantId");
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date reconcileBeginDate = dateFormat.parse(requestJO.getString("reconcileBeginDate"));
        Date reconcileEndDate = getAddDay(dateFormat.parse(requestJO.getString("reconcileEndDate")));
        //取结果集
        List<Map> resultList = merchantSettlementDao.findAccountsReceivable(merchantId, reconcileBeginDate, reconcileEndDate, page, size);
        Object count = merchantSettlementDao.findAccountsReceivableCount(merchantId, reconcileBeginDate, reconcileEndDate);
        object.put("content", resultList);
        object.put("total", count);
        object.put("pages", count);
        return object;
    }

    /**
     * 获取营业款
     *
     * @param request
     * @return
     * @throws ParseException
     */
    public JSONObject findBusinessMoney(SimpleRequest request) throws ParseException {
        JSONObject requestJO = request.getJO();
        int page = 0;
        int size = 50;
        if (requestJO.containsKey("data")) {
            requestJO = requestJO.getJSONObject("data");
            page = (int) request.getJO().get("page");
            size = (int) request.getJO().get("size");
        }
        JSONObject object = new JSONObject();
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date reconcileBeginDate = dateFormat.parse(requestJO.getString("reconcileBeginDate"));
        Date reconcileEndDate = getAddDay(dateFormat.parse(requestJO.getString("reconcileEndDate")));

        List<Map> resultList = merchantSettlementDao.findBusinessMoney(requestJO, reconcileBeginDate, reconcileEndDate, page, size);
        Object count = merchantSettlementDao.findBusinessMoneyCount(requestJO, reconcileBeginDate, reconcileEndDate);
        object.put("content", resultList);
        object.put("total", count);
        object.put("pages", count);
        return object;
    }
  /**
     * 获取委托定损成本明细
     *
     * @param request
     * @return
     * @throws ParseException
     */
    public JSONObject findLossAssessmentCost(SimpleRequest request) throws ParseException {
        JSONObject requestJO = request.getJO();
        int page = 0;
        int size = 50;
        if (requestJO.containsKey("data")) {
            requestJO = requestJO.getJSONObject("data");
            page = (int) request.getJO().get("page");
            size = (int) request.getJO().get("size");
        }
        JSONObject object = new JSONObject();
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date reconcileBeginDate = dateFormat.parse(requestJO.getString("reconcileBeginDate"));
        Date reconcileEndDate = getAddDay(dateFormat.parse(requestJO.getString("reconcileEndDate")));

        List<Map> resultList = merchantSettlementDao.findLossAssessmentCost(requestJO, reconcileBeginDate, reconcileEndDate, page, size);
        Object count = merchantSettlementDao.findLossAssessmentCostCount(requestJO, reconcileBeginDate, reconcileEndDate);
        object.put("content", resultList);
        object.put("total", count);
        object.put("pages", count);
        return object;
    }

    /**
     * 获取平台服务费减免明细
     *
     * @param request
     * @return
     * @throws ParseException
     */
    public JSONObject findFeeReducedDetail(SimpleRequest request) throws ParseException {
        JSONObject requestJO = request.getJO();
        int page = 0;
        int size = 50;
        if (requestJO.containsKey("data")) {
            requestJO = requestJO.getJSONObject("data");
            page = (int) request.getJO().get("page");
            size = (int) request.getJO().get("size");
        }
        JSONObject object = new JSONObject();
        String merchantId = requestJO.getString("merchantId");
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date reconcileBeginDate = dateFormat.parse(requestJO.getString("reconcileBeginDate"));
        Date reconcileEndDate = getAddDay(dateFormat.parse(requestJO.getString("reconcileEndDate")));

        List<Map> resultList = merchantSettlementDao.findFeeReducedDetail(merchantId, reconcileBeginDate, reconcileEndDate, page, size);
        Object count = merchantSettlementDao.findFeeReducedDetailCount(merchantId, reconcileBeginDate, reconcileEndDate);
        object.put("content", resultList);
        object.put("total", count);
        object.put("pages", count);
        return object;
    }

    /**
     * 获取天猫平台费付款明细
     *
     * @param request
     * @return
     * @throws ParseException
     */
    public JSONObject findTmallPlatformFee(SimpleRequest request) throws ParseException {
        JSONObject object = new JSONObject();
        JSONObject parameters = parseParameters(request);
        JSONObject condition = (JSONObject) request.get("condition");
        List<Map> filters = (List<Map>) condition.get("filters");
        filters.forEach(filter -> {
            parameters.put((String) filter.get("field"), filter.get("value"));
        });
        String merchantId = parameters.getString("merchantId");
        String channelId = parameters.getString("costSummaryType").equals("tmallPlatformFee")?"100":"75";
        List<Map> resultList = merchantSettlementDao.findPlatformFeeByChannel(merchantId,channelId, parameters.getDate("reconcileBeginDate"), parameters.getDate("reconcileEndDate"), parameters.getInteger("page"), parameters.getInteger("size"));
        Object count = merchantSettlementDao.findPlatformFeeByChannelCount(merchantId,channelId, parameters.getDate("reconcileBeginDate"), parameters.getDate("reconcileEndDate"));
        object.put("content", resultList);
        object.put("total", count);
        object.put("pages", count);
        return object;
    }

    /**
     * 获取车险销售额费用明细
     *
     * @param request
     * @return
     * @throws ParseException
     */
    public Page<InsuranceOrder> findInsuranceManagementFee(SimpleRequest request) throws ParseException {
        JSONObject parameters = parseParameters(request);
        String merchantId = parameters.getString("merchantId");
        Page<InsuranceOrder> insuranceOrders = insuranceOrderRepository.findByCompany(merchantId, parameters.getDate("reconcileBeginDate"), parameters.getDate("reconcileEndDate"), PageRequest.of(parameters.getInteger("page") - 1, parameters.getInteger("size")));
        return insuranceOrders;
    }

//    /**
//     * 获取采购变价账单明细
//     *
//     * @param request
//     * @return
//     * @throws ParseException
//     */
//    public Page<Invoice> findPriceChangeInvoice(SimpleRequest request) throws ParseException {
//        JSONObject parameters = parseParameters(request);
//        String merchantId = parameters.getString("merchantId");
//        Page<Invoice> invoices = invoiceRepository.findAllByCompanyAndOriginBusinessType(merchantId, "PriceChange", parameters.getDate("reconcileBeginDate"), parameters.getDate("reconcileEndDate"), PageRequest.of(parameters.getInteger("page") - 1, parameters.getInteger("size")));
//        return invoices;
//    }

    /**
     * 获取定损管理费明细
     *
     * @param request
     * @return
     * @throws ParseException
     */
    public JSONObject findQuotationExpense(SimpleRequest request) throws ParseException {
        JSONObject object = new JSONObject();
        JSONObject parameters = parseParameters(request);
        String merchantId = parameters.getString("merchantId");
        List<Map> resultList = merchantSettlementDao.findQuotationExpense(merchantId, parameters.getDate("reconcileBeginDate"), parameters.getDate("reconcileEndDate"), parameters.getInteger("page"), parameters.getInteger("size"));
        Object count = merchantSettlementDao.findQuotationExpenseCount(merchantId, parameters.getDate("reconcileBeginDate"), parameters.getDate("reconcileEndDate"));
        object.put("content", resultList);
        object.put("total", count);
        object.put("pages", count);
        return object;
    }

    /**
     * 查询供应链管理费明细
     *
     * @param request
     * @return
     */
    public JSONObject findManagementFee(SimpleRequest request) throws ParseException {
        JSONObject object = new JSONObject();
        JSONObject parameters = parseParameters(request);
        //取结果集
        List<Map> resultList = merchantSettlementDao.findManagementFee(parameters.getString("merchantId"), parameters.getDate("reconcileBeginDate"), parameters.getDate("reconcileEndDate"), parameters.getInteger("page"), parameters.getInteger("size"));
        Object count = merchantSettlementDao.findManagementFeCount(parameters.getString("merchantId"), parameters.getDate("reconcileBeginDate"), parameters.getDate("reconcileEndDate"));
        object.put("content", resultList);
        object.put("total", count);
        object.put("pages", count);
        return object;
    }

    /**
     * 查询会员跨公司消费-收入明细
     *
     * @param request
     * @return
     */
    public JSONObject findCrossCompanyIncome(SimpleRequest request) throws ParseException {
        JSONObject requestJO = request.getJO();
        int page = 0;
        int size = 50;
        if (requestJO.containsKey("data")) {
            requestJO = requestJO.getJSONObject("data");
            page = (int) request.getJO().get("page");
            size = (int) request.getJO().get("size");
        }
        JSONObject object = new JSONObject();
        String merchantId = requestJO.getString("merchantId");
        if (merchantId == null) {
            merchantId = requestJO.getJSONObject("merchant").getString("id");
        }
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date reconcileBeginDate = dateFormat.parse(requestJO.getString("reconcileBeginDate"));
        Date reconcileEndDate = getAddDay(dateFormat.parse(requestJO.getString("reconcileEndDate")));
        //取结果集
        List<Map> resultList = merchantSettlementDao.findCrossCompanyIncome(merchantId, reconcileBeginDate, reconcileEndDate, page, size);
        Object count = merchantSettlementDao.findCrossCompanyIncomeCount(merchantId, reconcileBeginDate, reconcileEndDate);
        object.put("content", resultList);
        object.put("total", count);
        object.put("pages", count);
        return object;
    }

    /**
     * 查询会员跨公司消费-收支出明细
     *
     * @param request
     * @return
     */
    public JSONObject findCrossCompanyPay(SimpleRequest request) throws ParseException {
        JSONObject requestJO = request.getJO();
        int page = 0;
        int size = 50;
        if (requestJO.containsKey("data")) {
            requestJO = requestJO.getJSONObject("data");
            page = (int) request.getJO().get("page");
            size = (int) request.getJO().get("size");
        }
        JSONObject object = new JSONObject();
        String merchantId = requestJO.getString("merchantId");
        if (merchantId == null) {
            merchantId = requestJO.getJSONObject("merchant").getString("id");
        }
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date reconcileBeginDate = dateFormat.parse(requestJO.getString("reconcileBeginDate"));
        Date reconcileEndDate = getAddDay(dateFormat.parse(requestJO.getString("reconcileEndDate")));
        //取结果集
        List<Map> resultList = merchantSettlementDao.findCrossCompanyPay(merchantId, reconcileBeginDate, reconcileEndDate, page, size);
        Object count = merchantSettlementDao.findCrossCompanyPayCount(merchantId, reconcileBeginDate, reconcileEndDate);
        object.put("content", resultList);
        object.put("total", count);
        object.put("pages", count);
        return object;
    }

    /**
     * 查询费用明细
     *
     * @param request
     * @return
     */
    public JSONObject findExpense(SimpleRequest request) {
        JSONObject object = new JSONObject();
        JSONObject requestJO = request.getJO();
        JSONObject data = requestJO.getJSONObject("data");
        List<Map> list = new ArrayList<>();
        if (data.containsKey("id") && data.getString("id") != null) {
            String id = data.getString("id");
            MerchantSettlement merchantSettlement = merchantSettlementRepository.findOne(id);
            merchantSettlement.getMerchantExpenseItems().forEach(merchantExpenseItem -> {
                JSONObject result = new JSONObject();
                result.put("id", merchantExpenseItem.getExpenseItem().getExpense().getId());
                result.put("name", merchantExpenseItem.getExpenseItem().getExpenseType().getName());
                result.put("tenant", merchantExpenseItem.getExpenseItem().getCompany().getName());
                result.put("amount", merchantExpenseItem.getExpenseItem().getAmount());
                result.put("withholdingAmount", merchantExpenseItem.getExpenseItem().getWithholdingAmount());
                result.put("amountDeducted", merchantExpenseItem.getExpenseItem().getAmountDeducted());
                result.put("note", merchantExpenseItem.getExpenseItem().getRemark());
                result.put("annex", merchantExpenseItem.getExpenseItem().getAnnex());
                result.put("periodStart", Objects.isNull(merchantExpenseItem.getExpenseItem().getPeriodStart()) ? null : DateUtil.format(merchantExpenseItem.getExpenseItem().getPeriodStart(), "yyyy-MM-dd"));
                result.put("periodEnd", Objects.isNull(merchantExpenseItem.getExpenseItem().getPeriodEnd()) ? null : DateUtil.format(merchantExpenseItem.getExpenseItem().getPeriodEnd(), "yyyy-MM-dd"));
                result.put("creator", Objects.isNull(merchantExpenseItem.getExpenseItem().getExpense().getCreator()) ? null : SpringManager.getBean(PartyRoleRepository.class).findOne(merchantExpenseItem.getExpenseItem().getExpense().getCreator()).getName());
                list.add(result);
            });
        } else {
            List<ExpenseItem> expenseItems = expenseItemRepository.findAllByExpenseCompany(data.getJSONObject("merchant").getString("id"));
            expenseItems.forEach(expenseItem -> {
                JSONObject result = new JSONObject();
                result.put("id", expenseItem.getExpense().getId());
                result.put("tenant", expenseItem.getCompany().getName());
                result.put("name", expenseItem.getExpenseType().getName());
                result.put("amount", expenseItem.getAmount());
                result.put("withholdingAmount", expenseItem.getWithholdingAmount());
                result.put("amountDeducted", expenseItem.getAmountDeducted());
                result.put("note", expenseItem.getRemark());
                result.put("annex", expenseItem.getAnnex());
                result.put("periodStart", Objects.isNull(expenseItem.getPeriodStart()) ? null : DateUtil.format(expenseItem.getPeriodStart(), "yyyy-MM-dd"));
                result.put("periodEnd", Objects.isNull(expenseItem.getPeriodEnd()) ? null : DateUtil.format(expenseItem.getPeriodEnd(), "yyyy-MM-dd"));
                result.put("creator", Objects.isNull(expenseItem.getExpense().getCreator()) ? null : SpringManager.getBean(PartyRoleRepository.class).findOne(expenseItem.getExpense().getCreator()).getName());
                list.add(result);
            });
        }

        object.put("content", list);
        return object;
    }

    /**
     * 查询借支明细
     *
     * @param request
     * @return
     */
    public JSONObject findBusiness(SimpleRequest request) {
        JSONObject object = new JSONObject();
        JSONObject requestJO = request.getJO();
        JSONObject data = requestJO.getJSONObject("data");
        List<Map> list = new ArrayList<>();
        if (data.containsKey("id") && data.getString("id") != null) {
            String id = data.getString("id");
            MerchantSettlement merchantSettlement = merchantSettlementRepository.findOne(id);
            merchantSettlement.getMerchantBusinessDebitItems().forEach(merchantBusinessDebitItem -> {
                JSONObject result = new JSONObject();
                result.put("id", merchantBusinessDebitItem.getBusinessDebitNote().getId());
                result.put("accessProvider", merchantBusinessDebitItem.getBusinessDebitNote().getAccessProvider().getName());
                result.put("fnCustomer", merchantBusinessDebitItem.getBusinessDebitNote().getFnCustomer().getName());
                result.put("numberOfStore", merchantBusinessDebitItem.getBusinessDebitNote().getNumberOfStore());
                result.put("availableLoan", merchantBusinessDebitItem.getBusinessDebitNote().getAvailableLoan());
                result.put("reason", merchantBusinessDebitItem.getBusinessDebitNote().getReason());
                result.put("priceDebit", merchantBusinessDebitItem.getBusinessDebitNote().getPriceDebit());
                result.put("principalRepaid", merchantBusinessDebitItem.getBusinessDebitNote().getPrincipalRepaid());
                result.put("unpaidPrincipal", merchantBusinessDebitItem.getBusinessDebitNote().getUnpaidPrincipal());

                list.add(result);
            });
        } else {
            List<BusinessDebitNote> businessDebitNotes = businessDebitNoteRepository.findAllByFnCustomerId(data.getJSONObject("merchant").getString("id"));
            businessDebitNotes.forEach(businessDebitNote -> {
                JSONObject result = new JSONObject();
                result.put("id", businessDebitNote.getId());
                result.put("fnCustomer", businessDebitNote.getFnCustomer().getName());
                result.put("accessProvider", businessDebitNote.getAccessProvider().getName());
                result.put("numberOfStore", businessDebitNote.getNumberOfStore());
                result.put("availableLoan", businessDebitNote.getAvailableLoan());
                result.put("reason", businessDebitNote.getReason());
                result.put("priceDebit", businessDebitNote.getPriceDebit());
                result.put("principalRepaid", businessDebitNote.getPrincipalRepaid());
                result.put("unpaidPrincipal", businessDebitNote.getUnpaidPrincipal());
                list.add(result);
            });
        }

        object.put("content", list);
        return object;
    }

    /**
     * 解析前端传来的参数
     *
     * @param request
     * @return
     * @throws ParseException
     */
    private JSONObject parseParameters(SimpleRequest request) throws ParseException {
        JSONObject requestJO = request.getJO();
        JSONObject result = new JSONObject();
        JSONObject data = requestJO.getJSONObject("data");
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        result.put("merchantId", data.getJSONObject("merchant").getString("id"));
        result.put("reconcileBeginDate", dateFormat.parse(data.getString("reconcileBeginDate")));
        result.put("reconcileEndDate", getAddDay(dateFormat.parse(data.getString("reconcileEndDate"))));
        result.put("page", requestJO.get("page"));
        result.put("size", requestJO.get("size"));

        return result;
    }

    /**
     * 查询应收账款(内)分类明细
     *
     * @return
     */
    public JSONObject findReceivableInMxType(SimpleRequest request) {
        JSONObject param = request.getJO().getJSONObject("data").getJSONObject("node");
        JSONObject object = new JSONObject();
        JSONArray tableHeader = new JSONArray();
        Map DEPT_NAME = MapUtil.mapper("field", "DEPT_NAME",
                "headerName", "部门名称", "width", 220
        );
        tableHeader.add(DEPT_NAME);

        Map ACCOUNTTYPE = MapUtil.mapper("field", "ACCOUNTTYPE",
                "headerName", "挂账类型", "width", 90
        );
        tableHeader.add(ACCOUNTTYPE);

        Map api = MapUtil.mapper("api", "fn.merchant.find.receivableInMx");
        Map AMOUNT = MapUtil.mapper("field", "AMOUNT",
                "headerName", "营业额", "width", 90, "sum", true, "cellRenderer", "link", "cellEditorParams", api
        );
        tableHeader.add(AMOUNT);

        Map COMPANY_NAME = MapUtil.mapper("field", "COMPANY_NAME",
                "headerName", "公司名称", "width", 280
        );
        tableHeader.add(COMPANY_NAME);
        List<Map> array = null;
        array = merchantSettlementDao.find_receivableInMxType(param.getDate("START_DATE"), param.getDate("END_DATE"), param.get("COMPANY_ID").toString(), param.getString("DEPT_ID"));

        object.put("tableHeader", tableHeader);
        object.put("content", array);
        return object;
    }

    /**
     * 查询应收账款(内)明细
     *
     * @return
     */
    public JSONObject findReceivableInMx(SimpleRequest request) {
        JSONObject param = request.getJO().getJSONObject("data").getJSONObject("node");
        JSONObject object = new JSONObject();
        JSONArray tableHeader = new JSONArray();
        Map DATE_OF_STATISTICS = MapUtil.mapper("field", "DATE_OF_STATISTICS",
                "headerName", "统计日期", "width", 110
        );
        tableHeader.add(DATE_OF_STATISTICS);

        Map DEPT_NAME = MapUtil.mapper("field", "DEPT_NAME",
                "headerName", "部门名称", "width", 220
        );
        tableHeader.add(DEPT_NAME);

        Map ACCOUNTTYPE = MapUtil.mapper("field", "ACCOUNTTYPE",
                "headerName", "挂账类型", "width", 90
        );
        tableHeader.add(ACCOUNTTYPE);

        Map api = MapUtil.mapper("api", "rcl.businessAmt.receivableInMxGdj");
        Map AMOUNT = MapUtil.mapper("field", "AMOUNT",
                "headerName", "营业额", "width", 90, "sum", true, "cellRenderer", "link", "cellEditorParams", api
        );
        tableHeader.add(AMOUNT);

        Map COMPANY_NAME = MapUtil.mapper("field", "COMPANY_NAME",
                "headerName", "公司名称", "width", 280
        );
        tableHeader.add(COMPANY_NAME);
        List<Map> array = null;
        array = merchantSettlementDao.find_receivableInMx(param.getDate("START_DATE"), getAddDay(param.getDate("END_DATE")), param.get("COMPANY_ID").toString(), param.getString("DEPT_ID"), param.getString("ACCOUNTTYPE"));

        object.put("tableHeader", tableHeader);
        object.put("content", array);
        return object;
    }

    /**
     * 查询货币资金明细
     *
     * @return
     */
    public JSONObject findPaymentMxType(SimpleRequest request) {
        JSONObject param = request.getJO().getJSONObject("data").getJSONObject("node");
        JSONObject object = new JSONObject();
        JSONArray tableHeader = new JSONArray();
        Map DEPT_NAME = MapUtil.mapper("field", "DEPT_NAME",
                "headerName", "部门名称", "width", 220
        );
        tableHeader.add(DEPT_NAME);

        Map PAYMENT_METHOD_TYPE_NAME = MapUtil.mapper("field", "PAYMENT_METHOD_TYPE_NAME",
                "headerName", "收款方式", "width", 90
        );
        tableHeader.add(PAYMENT_METHOD_TYPE_NAME);

        Map api = MapUtil.mapper("api", "fn.merchant.find.paymentMx");
        Map ZJ_AMT = MapUtil.mapper("field", "ZJ_AMT",
                "headerName", "货币资金（不含定损代收）", "width", 190, "sum", true, "cellRenderer", "link", "cellEditorParams", api
        );
        tableHeader.add(ZJ_AMT);

        Map AMOUNT = MapUtil.mapper("field", "AMOUNT",
                "headerName", "收款金额", "width", 90, "sum", true
        );
        tableHeader.add(AMOUNT);

        Map DS_AMT = MapUtil.mapper("field", "DS_AMT",
                "headerName", "定损代收", "width", 90, "sum", true
        );
        tableHeader.add(DS_AMT);

        Map COMPANY_NAME = MapUtil.mapper("field", "COMPANY_NAME",
                "headerName", "公司名称", "width", 280
        );
        tableHeader.add(COMPANY_NAME);
        List<Map> array = null;
        array = merchantSettlementDao.findPaymentMxType(param.getDate("START_DATE"), param.getDate("END_DATE"), param.get("COMPANY_ID").toString(), param.getString("DEPT_ID"));

        object.put("tableHeader", tableHeader);
        object.put("content", array);
        return object;
    }

    /**
     * 查询货币资金明细
     *
     * @return
     */
    public JSONObject findPaymentMx(SimpleRequest request) {
        JSONObject object = new JSONObject();
        JSONArray tableHeader = new JSONArray();
        Map DATE_OF_STATISTICS = MapUtil.mapper("field", "DATE_APPROVE",
                "headerName", "统计日期", "width", 110
        );
        tableHeader.add(DATE_OF_STATISTICS);

        Map DEPT_NAME = MapUtil.mapper("field", "DEPT_NAME",
                "headerName", "部门名称", "width", 220
        );
        tableHeader.add(DEPT_NAME);

        Map PAYMENT_METHOD_TYPE_NAME = MapUtil.mapper("field", "PAYMENT_METHOD_TYPE_NAME",
                "headerName", "收款方式", "width", 90
        );
        tableHeader.add(PAYMENT_METHOD_TYPE_NAME);

        Map api = MapUtil.mapper("api", "rcl.businessAmt.paymentMxGdj");
        Map ZJ_AMT = MapUtil.mapper("field", "ZJ_AMT",
                "headerName", "货币资金（不含定损代收）", "width", 190, "sum", true, "cellRenderer", "link", "cellEditorParams", api
        );
        tableHeader.add(ZJ_AMT);

        Map AMOUNT = MapUtil.mapper("field", "AMOUNT",
                "headerName", "收款金额", "width", 90, "sum", true
        );
        tableHeader.add(AMOUNT);

        Map DS_AMT = MapUtil.mapper("field", "DS_AMT",
                "headerName", "定损代收", "width", 90, "sum", true
        );
        tableHeader.add(DS_AMT);

        Map COMPANY_NAME = MapUtil.mapper("field", "COMPANY_NAME",
                "headerName", "公司名称", "width", 280
        );
        tableHeader.add(COMPANY_NAME);
        JSONArray array = null;
        JSONObject condition = (JSONObject) request.get("condition");
        List<Map> filters = (List<Map>) condition.get("filters");
        JSONObject model = new JSONObject();
        filters.forEach(filter -> model.put((String) filter.get("field"), filter.get("value")));
        JSONObject node = ((JSONObject) request.get("data")).getJSONObject("node");
        model.put("DATE_OF_STATISTICS_STATE", node.get("DATE_OF_STATISTICS_STATE"));
        model.put("DATE_OF_STATISTICS_END", node.get("DATE_OF_STATISTICS_END"));
        try {
            array = SpringManager.getBean(ReportDaliyDao.class).paymentMx(model);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        object.put("tableHeader", tableHeader);
        object.put("content", array);
        return object;
    }

    /**
     * 查询平台服务费减免项目明细
     *
     * @return
     */
    public JSONObject findFeeReducedItem(SimpleRequest request) throws ParseException {
        JSONObject requestJO = request.getJO();
        JSONObject param = requestJO.getJSONObject("data").getJSONObject("node");
        JSONArray tableHeader = new JSONArray();
        tableHeader.add(MapUtil.mapper("field", "V_ID",
                "headerName", "业务凭证", "width", 150
        ));
        tableHeader.add(MapUtil.mapper("field", "BUSINESS_NAME",
                "headerName", "业务类型", "width", 100
        ));

        tableHeader.add(MapUtil.mapper("field", "ID",
                "headerName", "源单据", "width", 140,"cellRenderer", "dialogButton", "buttonList", "[\n" +
                        "                           {\n" +
                        "                           'id':'search',\n" +
                        "                           'name':'',\n" +
                        "                           'hide':'false',\n" +
                        "                           'disabled':'false',\n" +
                        "                           'action': 'link',\n" +
                        "                           'link':'true'," +
                        "                          'api':'data.ORIGIN_BUSINESS_TYPE == `服务方案` ? `form/crm.servicePlanItem` :data.ORIGIN_BUSINESS_TYPE == `零售退回` ? `form/retail.saleReturnWithOrder` : `form/retail.order`',\n" +
//                  "  'config':{'OAInterface':false,'api':'data.ORIGIN_BUSINESS_TYPE == `ServicePlan` ? `fn.service.findOne` :data.ORIGIN_BUSINESS_TYPE == `RetailReturn` ? `retail.returnWithOrder.findOne` : `retail.order.findOne`'}\n" +
                        "  'config':{'OAInterface':false,'api':'debugger;var a= data.ORIGIN_BUSINESS_TYPE == `服务方案` ? `fn.service.findOne` :data.ORIGIN_BUSINESS_TYPE == `零售退回` ? `retail.returnWithOrder.findOne` : `retail.order.findOne` ;" +
                        "             return a;'}\n" +
                        "                           }]"
        ));

        tableHeader.add(MapUtil.mapper("field", "ORIGIN_BUSINESS_TYPE",
                "headerName", "源单据类型", "width", 100
        ));

        tableHeader.add(MapUtil.mapper("field", "COMPANY_ID",
                "headerName", "公司编码", "width", 100
        ));

        tableHeader.add(MapUtil.mapper("field", "COMPANY_NAME",
                "headerName", "公司", "width", 220
        ));

        tableHeader.add(MapUtil.mapper("field", "PARTNER_NAME",
                "headerName", "合作伙伴", "width", 220
        ));

        tableHeader.add(MapUtil.mapper("field", "PRODUCT_CLASSIFY",
                "headerName", "品类", "width", 100
        ));

        tableHeader.add(MapUtil.mapper("field", "PRODUCT_ID",
                "headerName", "商品编码", "width", 120
        ));


        tableHeader.add(MapUtil.mapper("field", "PRODUCT_NAME",
                "headerName", "商品名称", "width", 280
        ));


        tableHeader.add(MapUtil.mapper("field", "PRICE_UNIT",
                "headerName", "单价", "width", 100
        ));

        tableHeader.add(MapUtil.mapper("field", "PRODUCT_QTY",
                "headerName", "数量", "width", 100
        ));

        tableHeader.add(MapUtil.mapper("field", "DISCOUNT",
                "headerName", "折扣", "width", 100, "sum", true
        ));

        tableHeader.add(MapUtil.mapper("field", "PRICE_TOTAL",
                "headerName", "总金额", "width", 100, "sum", true
        ));

        tableHeader.add(MapUtil.mapper("field", "PLATFORM_MANAGEMENT_FEE",
                "headerName", "平台服务费", "width", 100, "sum", true
        ));


        tableHeader.add(MapUtil.mapper("field", "PLATFORM_SERVICE_FEE_REDUCED",
                "headerName", "减免金额", "width", 100,   "sum", true
        ));


        tableHeader.add(MapUtil.mapper("field", "CREATE_DATE",
                "headerName", "业务发生日期", "width", 220
        ));
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        Date start_date = dateFormat.parse(param.getString("START_DATE"));
        Date end_date = dateFormat.parse(param.getString("END_DATE"));
        String productClassify = param.getString("PRODUCT_CLASSIFY");
        String companyId = param.getString("COMPANY_ID");
        List<Map> resultList = merchantSettlementDao.findFeeReducedItem(companyId, productClassify, start_date, end_date, requestJO.getInteger("page"), requestJO.getInteger("size"));
        Object count = merchantSettlementDao.findFeeReducedItemCount(companyId, productClassify, start_date, end_date);
        JSONObject object = new JSONObject();
        object.put("tableHeader", tableHeader);
        object.put("content", resultList);
        object.put("total", count);
        object.put("pages", count);

        return object;
    }

}
